﻿//-----------------------------------------------------------------------
// <copyright file="Domain.cs" company="FPTSS">
//     Copyright FPTSS. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace ExtSite
{
    using System;
    using System.DirectoryServices;
    using ActiveDs;

    /// <summary>
    /// Content all function of active directories
    /// </summary>
    public class ClsDomain
    {
        /// <summary>
        /// Authenticate domain user
        /// </summary>
        /// <param name="userName">domain username</param>
        /// <param name="password">domain password</param>
        /// <param name="domain">domain name</param>
        /// <returns>true of false</returns>
        public static bool Authenticate(string userName, string password, string domain)
        {
            bool authentic = false;
            try
            {
                DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, userName, password);

                if (entry.NativeObject == null)
                {
                    return false;
                }

                object nativeObject = entry.NativeObject;
                DirectorySearcher search = new DirectorySearcher(entry);
                search.Filter = "(SAMAccountName=" + userName + ")";
                SearchResult ldaPresult = search.FindOne();
                entry = ldaPresult.GetDirectoryEntry();
                IADsUser intADsUser = (IADsUser)entry.NativeObject;
                authentic = true;
            }
            catch (Exception ex)
            {
                authentic = false;
                throw ex;
            }

            return authentic;
        }

        /// <summary>
        /// Add exist user to exist gruop in domain
        /// </summary>
        /// <param name="userDn">User want to add</param>
        /// <param name="groupDn">Gruop of domain</param>
        /// <returns></returns>
        public bool AddUserToGroup(string userDn, string groupDn)
        {
            bool Result = true;
            try
            {
                DirectoryEntry dirEntry = new DirectoryEntry("LDAP://" + groupDn);
                dirEntry.Properties["member"].Add(userDn);
                dirEntry.CommitChanges();
                dirEntry.Close();
            }
            catch (System.DirectoryServices.DirectoryServicesCOMException)
            {
                //doSomething with E.Message.ToString();
                Result = false;
                throw;
            }
            return Result;
        }

        /// <summary>
        /// Remove exist user from exist gruop in domain
        /// </summary>
        /// <param name="userDn">User want to add</param>
        /// <param name="groupDn">Gruop of domain</param>
        /// <returns></returns>
        public void RemoveUserFromGroup(string userDn, string groupDn)
        {
            try
            {
                DirectoryEntry dirEntry = new DirectoryEntry("LDAP://" + groupDn);
                dirEntry.Properties["member"].Remove(userDn);
                dirEntry.CommitChanges();
                dirEntry.Close();
            }
            catch (System.DirectoryServices.DirectoryServicesCOMException E)
            {
                //doSomething with E.Message.ToString();

            }
        }

        /// <summary>
        /// Create a domain user
        /// </summary>
        /// <param name="ldapPath">domain name</param>
        /// <param name="userName">user name</param>
        /// <param name="userPassword">user init password</param>
        /// <returns>GUIID of new user</returns>
        public string CreateUserAccount(string ldapPath, string userName, string userPassword)
        {
            string oGUID = string.Empty;
            try
            {
                string connectionPrefix = "LDAP://" + ldapPath;
                DirectoryEntry dirEntry = new DirectoryEntry(connectionPrefix);
                DirectoryEntry newUser = dirEntry.Children.Add
                    ("CN=" + userName, "user");
                newUser.Properties["samAccountName"].Value = userName;
                newUser.CommitChanges();
                oGUID = newUser.Guid.ToString();

                newUser.Invoke("SetPassword", new object[] { userPassword });
                newUser.CommitChanges();
                dirEntry.Close();
                newUser.Close();
            }
            catch (System.DirectoryServices.DirectoryServicesCOMException)
            {
                //DoSomethingwith --> E.Message.ToString();
                throw;
            }
            return oGUID;
        }

        /// <summary>
        /// Reset user domain password
        /// </summary>
        /// <param name="userDn">full user name EX: domain\username</param>
        /// <param name="password">new password</param>
        /// <returns>false or success</returns>
        public bool ResetPassword(string userDn, string password)
        {
            bool Result = true;
            try
            {
                DirectoryEntry uEntry = new DirectoryEntry(userDn);
                uEntry.Invoke("SetPassword", new object[] { password });
                uEntry.Properties["LockOutTime"].Value = 0; //unlock account
                uEntry.Close();
            }
            catch (Exception)
            {
                Result = false;
                throw;
            }
            return Result;
        }

        /// <summary>
        /// Enable user
        /// </summary>
        /// <param name="userDn">user name</param>
        /// <returns>success or false</returns>
        public bool Enable(string userDn)
        {
            bool Result = true;
            try
            {
                DirectoryEntry user = new DirectoryEntry(userDn);
                int val = (int)user.Properties["userAccountControl"].Value;
                user.Properties["userAccountControl"].Value = val & ~0x2;
                //ADS_UF_NORMAL_ACCOUNT;

                user.CommitChanges();
                user.Close();
            }
            catch (System.DirectoryServices.DirectoryServicesCOMException)
            {
                //DoSomethingWith --> E.Message.ToString();
                Result = false;
                throw;
            }
            return Result;
        }

        /// <summary>
        /// Disable user
        /// </summary>
        /// <param name="userDn">user name</param>
        /// <returns>success or false</returns>
        public bool Disable(string userDn)
        {
            bool Result = true;
            try
            {
                DirectoryEntry user = new DirectoryEntry(userDn);
                int val = (int)user.Properties["userAccountControl"].Value;
                user.Properties["userAccountControl"].Value = val | 0x2;
                //ADS_UF_ACCOUNTDISABLE;

                user.CommitChanges();
                user.Close();
            }
            catch (System.DirectoryServices.DirectoryServicesCOMException)
            {
                //DoSomethingWith --> E.Message.ToString();
                Result = false;
                throw;
            }
            return Result;
        }


        #region Backup

        /*
        private static DateTime getpwdLastSet(DirectoryEntry entry, string username)
        {
            DirectorySearcher search = new DirectorySearcher(entry);
            search.Filter = "(SAMAccountName=" + username + ")";
            SearchResult ldaPresult = search.FindOne();
            entry = ldaPresult.GetDirectoryEntry();

            // Pulling the informtion on when the password was last changed and converting it to a LargeInteger. 
            LargeInteger liAcctPwdChange = entry.Properties["pwdLastSet"].Value as LargeInteger;

            // Convert the highorder/loworder parts of the property pulled to a long. 
            long dateAcctPwdChange = (((long)(liAcctPwdChange.HighPart) << 32) + (long)liAcctPwdChange.LowPart);

            // Convert FileTime to DateTime and get what today's date is. 
            DateTime dtNow = DateTime.Now;
            // I added 90 days because I know what my password expiration is set to, if not you need to pull that information and add the number of days it is set for. 
            DateTime dtAcctPwdChange = DateTime.FromFileTime(dateAcctPwdChange).AddDays(90);
            string strAcctPwdChange = DateTime.FromFileTime(dateAcctPwdChange).ToShortDateString();
            string strAcctPwdExpires = DateTime.FromFileTime(dateAcctPwdChange).AddDays(90).ToShortDateString();
            return dtAcctPwdChange;
        }

        public static string GetDomainPass(Binary bin)
        {
            return System.Text.Encoding.ASCII.GetString(bin.ToArray());
        }

        public static Binary GetDomainPassBinary(string pass)
        {
            return System.Text.Encoding.ASCII.GetBytes(pass);
        }

        public static string GetSid(string strDomain, string strName)
        {
            string str = "";
            DirectoryEntry obDirEntry = null;
            try
            {
                Int64 iBigVal = 5;
                Byte[] bigArr = BitConverter.GetBytes(iBigVal);
                obDirEntry = new DirectoryEntry("WinNT://" +
                                      strDomain + "/" + strName);
                System.DirectoryServices.PropertyCollection
                                   coll = obDirEntry.Properties;
                object obVal = coll["objectSid"].Value;
                if (null != obVal)
                {
                    str = ClsDomain.ConvertByteToStringSid((Byte[])obVal);
                }

            }
            catch (Exception ex)
            {
                str = "";
                Trace.Write(ex.Message);
            }
            return str;
        }
        public static string GetSid(string strLogin)
        {
            string str = "";
            // Parse the string to check if domain name is present.

            int idx = strLogin.IndexOf('\\');
            if (idx == -1)
            {
                idx = strLogin.IndexOf('@');
            }

            string strDomain;
            string strName;

            if (idx != -1)
            {
                strDomain = strLogin.Substring(0, idx);
                strName = strLogin.Substring(idx + 1);
            }
            else
            {
                strDomain = Environment.MachineName;
                strName = strLogin;
            }


            DirectoryEntry obDirEntry = null;
            try
            {
                Int64 iBigVal = 5;
                Byte[] bigArr = BitConverter.GetBytes(iBigVal);
                obDirEntry = new DirectoryEntry("WinNT://" +
                                      strDomain + "/" + strName);
                System.DirectoryServices.PropertyCollection
                                   coll = obDirEntry.Properties;
                object obVal = coll["objectSid"].Value;
                if (null != obVal)
                {
                    str = ClsDomain.ConvertByteToStringSid((Byte[])obVal);
                }

            }
            catch (Exception ex)
            {
                str = "";
                Trace.Write(ex.Message);
            }
            return str;
        }
        private static string ConvertByteToStringSid(Byte[] sidBytes)
        {
            StringBuilder strSid = new StringBuilder();
            strSid.Append("S-");
            try
            {
                // Add SID revision.

                strSid.Append(sidBytes[0].ToString());
                // Next six bytes are SID authority value.

                if (sidBytes[6] != 0 || sidBytes[5] != 0)
                {
                    string strAuth = String.Format
                        ("0x{0:2x}{1:2x}{2:2x}{3:2x}{4:2x}{5:2x}",
                        (Int16)sidBytes[1],
                        (Int16)sidBytes[2],
                        (Int16)sidBytes[3],
                        (Int16)sidBytes[4],
                        (Int16)sidBytes[5],
                        (Int16)sidBytes[6]);
                    strSid.Append("-");
                    strSid.Append(strAuth);
                }
                else
                {
                    Int64 iVal = (Int32)(sidBytes[1]) +
                        (Int32)(sidBytes[2] << 8) +
                        (Int32)(sidBytes[3] << 16) +
                        (Int32)(sidBytes[4] << 24);
                    strSid.Append("-");
                    strSid.Append(iVal.ToString());
                }

                // Get sub authority count...

                int iSubCount = Convert.ToInt32(sidBytes[7]);
                int idxAuth = 0;
                for (int i = 0; i < iSubCount; i++)
                {
                    idxAuth = 8 + i * 4;
                    UInt32 iSubAuth = BitConverter.ToUInt32(sidBytes, idxAuth);
                    strSid.Append("-");
                    strSid.Append(iSubAuth.ToString());
                }
            }
            catch (Exception ex)
            {
                Trace.Write(ex.Message);
                return "";
            }
            return strSid.ToString();
        }
        */

        #endregion Backup
    }

    public enum UserAccountControlFlags
    {
        SCRIPT = 0x0001,
        ACCOUNTDISABLE = 0x0002,
        HOMEDIR_REQUIRED = 0x0008,
        LOCKOUT = 0x0010,
        PASSWD_NOTREQD = 0x0020,
        PASSWD_CANT_CHANGE = 0x0040,
        ENCRYPTED_TEXT_PWD_ALLOWED = 0x0080,
        TEMP_DUPLICATE_ACCOUNT = 0x0100,
        NORMAL_ACCOUNT = 0x0200,
        INTERDOMAIN_TRUST_ACCOUNT = 0x0800,
        WORKSTATION_TRUST_ACCOUNT = 0x1000,
        SERVER_TRUST_ACCOUNT = 0x2000,
        DONT_EXPIRE_PASSWORD = 0x10000,
        MNS_LOGON_ACCOUNT = 0x20000,
        SMARTCARD_REQUIRED = 0x40000,
        TRUSTED_FOR_DELEGATION = 0x80000,
        NOT_DELEGATED = 0x100000,
        USE_DES_KEY_ONLY = 0x200000,
        DONT_REQ_PREAUTH = 0x400000,
        PASSWORD_EXPIRED = 0x800000,
        TRUSTED_TO_AUTH_FOR_DELEGATION = 0x1000000

    }
}
